package api_day13;

import java.util.concurrent.Semaphore;

public class DeadLockDemo {
    public static final Semaphore s1 = new Semaphore(1);
    public static final Semaphore s2 = new Semaphore(1);
    public static void main(String[] args) {
        Object o1 = new Object();
        Object o2 = new Object();
        //创造死锁现象
        /*new Thread("线程1"){
            @Override
            public void run() {
                System.out.println("这是线程：" + this.getName());
                synchronized (o1){
                    System.out.println("获得锁对象o1");
                    synchronized (o2){
                        System.out.println("获得锁对象o2");
                        try {
                            o1.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    System.out.println("释放锁");
                }
            }
        }.start();
        new Thread("线程2"){
            @Override
            public void run() {
                System.out.println("这是线程：" + this.getName());
                synchronized (o2){
                    System.out.println("获得锁对象o2");
                    synchronized (o1){
                        System.out.println("获得锁对象o1");
                        try {
                            o2.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    System.out.println("释放锁");
                }
            }
        }.start();*/
        //解决死锁现象
        /*//方法一：一次只上锁一个 - 有并发修改的风险，不建议使用
        new Thread("线程1"){
            @Override
            public void run() {
                System.out.println("这是线程：" + this.getName());
                synchronized (o1){
                    System.out.println("获得锁对象o1");
                    System.out.println("获得锁对象o2");
                    System.out.println("释放锁");
                }
            }
        }.start();
        new Thread("线程2"){
            @Override
            public void run() {
                System.out.println("这是线程：" + this.getName());
                synchronized (o2){
                    System.out.println("获得锁对象o2");
                    System.out.println("获得锁对象o1");
                    System.out.println("释放锁");
                }
            }
        }.start();*/
        /*//方法二：加锁顺序(按照线程顺序加锁)
        //        前提条件: 需要一次锁定多个资源对象
        //        解决方式: 可以根据资源对象的某个属性或hashCode()值来定义锁的先后顺序
        Runnable run = new Runnable(){
            @Override
            public void run() {
                if (o1.hashCode() > o2.hashCode()){
                    synchronized (o1){
                        System.out.println("获取锁对象o1");
                        synchronized (o2){
                            System.out.println("获取锁对象o2");
                        }
                        System.out.println("释放锁");
                    }
                }else {
                    synchronized (o2){
                        System.out.println("获取锁对象o2");
                        synchronized (o1){
                            System.out.println("获取锁对象o1");
                        }
                        System.out.println("释放锁");
                    }
                }
            }
        };
        new Thread(run,"线程1").start();
        new Thread(run,"线程2").start();*/
        //方法三：加锁时限(线程尝试获取锁的时候加上时间限制,超过时间则放弃对锁的请求,并释放自己占有的锁) - 使用Semaphore类
        //        new Semaphore(int permits)：确定资源数量
        //        boolean tryAcquire()：获取许可
        //        boolean tryAcquire(long timeout, TimeUnit unit)：获取许可，等待指定时间
        //        void release()：释放许可
        new Thread("线程1"){
            @Override
            public void run() {
                System.out.println("线程1开始执行");
                if (s1.tryAcquire()){
                    System.out.println("获取资源1，Lock锁锁住资源1");
                    if (s2.tryAcquire()){
                        System.out.println("获取资源2，Lock锁锁住资源2");
                    }
                }
                //释放许可
                s1.release();
                s2.release();
            }
        }.start();
        System.out.println("---------------------------");
        new Thread("线程2"){
            @Override
            public void run() {
                System.out.println("线程2开始执行");
                if (s2.tryAcquire()){
                    System.out.println("获取资源2，Lock锁锁住资源2");
                    if (s1.tryAcquire()){
                        System.out.println("获取资源1，Lock锁锁住资源1");
                    }
                }
                //释放许可
                s1.release();
                s2.release();
            }
        }.start();
    }
}